package com.recipedb.sprint.service.impl;

import com.recipedb.sprint.entity.Users;
import com.recipedb.sprint.repository.UsersRepository;
import com.recipedb.sprint.service.LlmSessionService;
import com.recipedb.sprint.service.SessionsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.util.Map;
import java.util.UUID;


import java.io.IOException;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
@RequiredArgsConstructor
public class SessionsServiceImpl implements SessionsService {

    private final UsersRepository usersRepository; // 仅用于校验用户存在（不依赖LlmSession的用户逻辑）
    private final LlmSessionService llmSessionService; // 复用LlmSession的LLM能力

    private final RedisTemplate<String, String> redisTemplate;

    // 汽车专家专用系统提示词（与购车咨询区分，在自身服务中定义，不侵入LlmSession）
    private static final String EXPERT_SYSTEM_PROMPT = "你是汽车领域专家，专注解答专业知识问题（如技术原理、术语解释、功能说明等）。回答需准确、简洁，用通俗语言解释。";


    @Override
    public String processQuestion(Long userId, String question, String model) {

        log.info("===== 汽车专家服务开始处理 =====");//
        log.info("userId={}, question={}, model={}", userId, question, model);//

        // 1. 校验用户存在（保留基础校验）
        Users user = usersRepository.findById(userId)
                .orElseThrow(() -> new IllegalArgumentException("用户不存在：" + userId));

        log.info("用户校验通过：{}", userId);//


        // 2. 清洗用户输入（避免编码问题）
        if (question != null) {
            question = question.replace("\u0000", "").replaceAll("[\\x00-\\x1F\\x7F]", "");
        }
        log.info("输入清洗完成：{}", question);//
        // 3. 核心逻辑：不拼接任何提示词，直接使用用户输入
       // String finalPrompt = question; // 普通对话输入直接给大模型


        log.info("开始调用 LlmSession.createSessionAndRunLlm");//

        // 4. 调用 LlmSession，固定传递 useSystemPrompt=false（不拼接、不落库）
        Map<String, Object> llmResult = llmSessionService.createSessionAndRunLlm(
                userId,
                //finalPrompt,
                question, // 直接传用户问题，不拼接提示词
                model,
                false, // 固定为false，与汽车咨询（true）区分
                null
        );

        log.info("LlmSession 调用返回：{}", llmResult); //

        String redisKey = (String) llmResult.get("redisKey");// 直接获取LlmSession返回的redisKey
        //Long sessionId = (Long) llmResult.get("sessionId"); // 此时必然为null，仅接收

        if (redisKey == null || redisKey.trim().isEmpty()) {
            log.error("LlmSession 返回的 redisKey 为空！");
            throw new IllegalArgumentException("LLM 会话创建失败");
        }
        log.info("获取 redisKey：{}", redisKey);//


        // 5. 异步清洗Redis中的大模型响应（确保输出干净）
        CompletableFuture.runAsync(() -> {
            try {
                String rawContent = redisTemplate.opsForValue().get(redisKey);
                if (rawContent != null) {
                    String cleanContent = rawContent.replace("\u0000", "").replaceAll("[\\x00-\\x1F\\x7F]", "");
                    redisTemplate.opsForValue().set(redisKey, cleanContent);
                }
            } catch (Exception e) {
                log.error("清洗Redis中LLM响应失败", e);
            }
        });

        // 6. 生成临时标识（固定格式：expert:temp:{redisKey}，标识不落库）
        String tempKey =  redisKey;
        log.info("🚗 汽车专家普通对话提交（不拼接提示词、不落库），tempKey={}, redisKey={}", tempKey, redisKey);

        return tempKey;
    }

    private String cleanLlmResponse(String response) {
        if (response == null) {
            return "";
        }
        // 移除空字节（0x00）和所有 ASCII 控制字符（彻底解决编码问题）
        return response.replace("\u0000", "")
                .replaceAll("[\\x00-\\x1F\\x7F]", "");
    }

   @Override
   public void streamAnswer(String tempKey, SseEmitter emitter) {
       try {
           // 直接使用tempKey作为Redis Key（无需拆分，与processQuestion返回的redisKey一致）
           String redisKey = tempKey;

           // 包装Emitter，清洗输出内容
           SseEmitter wrappedEmitter = new SseEmitter(0L) {
               @Override
               public void send(Object object) throws IOException {
                   if (object instanceof String) {
                       String cleanContent = cleanLlmResponse((String) object);
                       super.send(cleanContent);
                   } else {
                       super.send(object);
                   }
               }
           };

           // 调用LlmSession的RedisKey流式输出方法
           llmSessionService.streamSessionByRedisKey(redisKey, wrappedEmitter);
           log.info("📡 汽车专家流式输出启动，redisKey={}", redisKey);

       } catch (Exception e) {
           log.error("汽车专家流式输出失败", e);
           try {
               emitter.send(SseEmitter.event().name("error").data("输出失败：" + e.getMessage()));
               emitter.completeWithError(e);
           } catch (IOException ex) {
               log.error("发送错误事件失败", ex);
           }
       }
   }


}